package com.service.sys.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.config.globalException.BusinessException;
import com.entity.sys.*;
import com.mapper.sys.MenuMapper;
import com.service.sys.MenuRoleService;
import com.service.sys.MenuService;
import com.service.sys.RoleService;
import com.service.sys.UserRoleService;
import com.utils.RedisUtil;
import com.vo.sys.MenuWithAuth;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author clay
 * @since 2022-02-15
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private MenuRoleService menuRoleService;

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private RoleService roleService;

    @Override
    public MenuWithAuth getMenuByUserId() {
        // SecurityContextHolder.getContext().getAuthentication().getPrincipal() 获取的其实就是传入的User
        String id = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId();
        System.out.println("id: " + id);
        //从redis获取菜单数据
        // 菜单以及权限列表
        MenuWithAuth menuWithAuth =  JSON.toJavaObject((JSON) JSON.toJSON(redisUtil.get("menu_" + id)), MenuWithAuth.class);
        if (Objects.isNull(menuWithAuth)) {
            QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<UserRole>().eq(
                    "user_id", id
            );
            List<UserRole> userRoleList = userRoleService.list(userRoleQueryWrapper);
            List<MenuRole> menuRoleList = new ArrayList<>();
            for (UserRole userRole : userRoleList) {
                List<MenuRole> menuRoles = menuRoleService.list(new QueryWrapper<MenuRole>().eq(
                        "role_id", userRole.getRoleId()
                ));
                menuRoleList.addAll(menuRoles);
            }
            System.out.println("去重前的菜单" + JSON.toJSON(menuRoleList));
            //对menuId进行去重
            List<MenuRole> arrays = menuRoleList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()
                    -> new TreeSet<>(Comparator.comparing(MenuRole :: getMenuId))), ArrayList::new));
            System.out.println("去重后的菜单权限" + JSON.toJSON(arrays));
            List<Menu> menuList = new ArrayList<>();
            List<String> auths = new ArrayList<>();
            for (MenuRole array : arrays) {
                Menu menu = this.getById(array.getMenuId());
                menuList.add(menu);
                if (!StringUtils.isEmpty(menu.getAuthCode())) {
                    auths.add(menu.getAuthCode());
                }
            }

            List<Menu> menus = menuToTree(menuList);
            menuWithAuth = new MenuWithAuth(); //这里需要新建一个对象
            menuWithAuth.setAuths(auths);
            menuWithAuth.setMenus(menus);
            //过期时间1000s
            redisUtil.set("menu_" + id, menuWithAuth, 1000);
        }
        return menuWithAuth;
    }

    @Override
    public List<Menu> getMenuWithRole() {
//        List<Menu> menuWithRole = menuMapper.getMenuWithRole();
//        menuWithRole = (List<Menu>) redisUtil.get("all_menu");
//        if (CollectionUtil.isEmpty(menuWithRole)) {
//            menuWithRole = menuMapper.getMenuWithRole();
//            redisUtil.set("all_menu", menuWithRole, 1000);
//        }
        Object allAuth = redisUtil.get("allAuth");
        List<Menu> menuWithRole;
        if (Objects.isNull(allAuth)) {
            menuWithRole = new ArrayList<>();
            List<Menu> menuList = this.list(new QueryWrapper<Menu>().isNotNull("url"));
            for (Menu menu : menuList) {
                List<MenuRole> menuRoleList = menuRoleService.list(new QueryWrapper<MenuRole>().eq(
                        "menu_id", menu.getId()
                ));
                List<Role> roles = new ArrayList<>();
                for (MenuRole menuRole : menuRoleList) {
                    roles.add(roleService.getById(menuRole.getRoleId()));
                }
                menu.setRoles(roles);
                menuWithRole.add(menu);
            }
            redisUtil.set("allAuth", menuWithRole, 1000);
            return menuWithRole;
        }
        return (List<Menu>) JSONArray.parseArray(JSONArray.toJSONString(allAuth), Menu.class);
    }

    @Override
    public Boolean deleteMenu(String id) {
        List<Menu> menus = this.list(new QueryWrapper<Menu>().eq(
                "parent_id", id
        ));
        List<MenuRole> menuRoleList = new ArrayList<>();
        if (menus.size() > 0) {
            for (Menu menu : menus) {
                List<MenuRole> menuRoles = menuRoleService.list(new QueryWrapper<MenuRole>().eq(
                        "menu_id", id
                ));
                menuRoleList.addAll(menuRoles);
            }
        }
        List<MenuRole> menuRoles = menuRoleService.list(new QueryWrapper<MenuRole>().eq(
                "menu_id", id
        ));
        menuRoleList.addAll(menuRoles);
        if (menuRoleList.size() > 0) {
            throw new BusinessException("存在被引用的菜单, 无法删除");
        }

        return this.removeById(id);
    }

    @Override
    public List<Menu> getList() {
        List<Menu> menuList = this.list();
        return menuToTree(menuList);
    }

    /**
     * 将查询到菜单返回成一根树。
     *
     * @param menus
     * @return
     */
    public static List<Menu> menuToTree(List<Menu> menus) {
        List<Menu> menuList = new ArrayList<>();
        for (Menu menu : menus) {
            //找到所有的父节点
            if ("0".equals(menu.getParentId()) || Objects.isNull(menu.getParentId())) {
                List<Menu> childrenTree = getChildrenTree(menus, menu.getId());
                menu.setChildren(childrenTree);
                menuList.add(menu);
            }
        }
        return menuList;
    }

    /**
     * 递归找到所有子节点
     *
     * @param menus
     * @param id
     * @return
     */
    public static List<Menu> getChildrenTree(List<Menu> menus, String id) {
        List<Menu> menuList = new ArrayList<>();
        for (Menu menu : menus) {
            if (id.equals(menu.getParentId())) {
                List<Menu> childrenTree = getChildrenTree(menus, menu.getId());
                menu.setChildren(childrenTree);
                menuList.add(menu);
            }
        }
        return menuList;
    }

}
